Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overload docs #3159

Merged
merged 3 commits into from
Apr 12, 2017
Merged

Overload docs #3159

merged 3 commits into from
Apr 12, 2017

Conversation

gvanrossum
Copy link
Member

This is based on PR #2792 by @jkleint. It documents the feature added in PR @2603 by @sixolet.

@sixolet, @ilevkivskyi, @pkch -- any comments on this version?

jkleint and others added 2 commits April 12, 2017 10:33
The docs say `@override` doesn't work in user code, but it seems to work in mypy 0.470.
The update may be waiting on #2603, but that PR does not seem to include doc updates,
so feel free to put this patch in that PR.
Copy link
Collaborator

@sixolet sixolet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. I especially like the __getitem__ motivation, because it's a thing the user is quite likely to run into, unlike trying to redefine abs.

My commentary is mostly picky wordsmithing stuff, and as such is a matter of judgement. Take that of it which seems to make the writing clearer, and leave the rest.

my_abs = abs
my_abs(-2) # 2 (int)
my_abs(-1.5) # 1.5 (float)
they still define a single runtime object. There is no multiple
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/multiple/automatic/

The user does implement dispatch in their implementation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and also: this is single dispatch rather than multiple dispatch, since only one argument determines the implementation. But the sentence should apply to both single and multiple dispatch of course.

my_abs(-2) # 2 (int)
my_abs(-1.5) # 1.5 (float)
they still define a single runtime object. There is no multiple
dispatch happening, and you must manually handle the different types
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"manually handle the different types in the implementation"

else:
assert False, "Unsupported argument %r" % (index,)

But this is a little loose, as it implies that when you put in an
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/a little/too/

pass # Don't put code here

# All overloads and the implementation must be adjacent
# in the source file, and overload order may matter.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider explaining how overload order matters -- without doing so it feels like a warning against using overloading, because stuff you don't understand might happen.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #1270 (comment) for some background.

def __getitem__(self, index: slice) -> Sequence[T]:
pass # Don't put code here

# Actual implementation goes last, without @overload.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/Actual/The/

elif isinstance(index, slice):
... # Return a sequence of Ts here
else:
assert False, "Unsupported argument %r" % (index,)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

raise TypeError("Unsupported index type '%s'" % index.__class__.__name__) or something like that is closer to what Python does in the builtin types.

yet) using the ``@overload`` decorator. For example, we can define an
``abs`` function that works for both ``int`` and ``float`` arguments:
Sometimes the types in a function depend on each other in ways that
can't be captured with a simple ``Union``. For example, the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/simple//


But this is a little loose, as it implies that when you put in an
``int`` you might sometimes get out a single item or sometimes a
sequence. To capture a constraint such as a return type that depends
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like your sentence structure here is a bit convoluted, and it might do to mention a type variable as another option here -- it's preferable when it's possible. Perhaps:

"The return type depends on the parameter type in a way that can't be expressed by a type variable. We can use overloading (link) to give the same function multiple type annotations (signatures) and accurately describe the function's behavior."

Or something -- wordsmithing is hard. My confidence that this version is better than yours is only about 70%.

@gvanrossum
Copy link
Member Author

OK, how about now?

Copy link
Collaborator

@sixolet sixolet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it!

@gvanrossum gvanrossum merged commit 01bb4c1 into master Apr 12, 2017
@gvanrossum gvanrossum deleted the overload-docs branch April 12, 2017 19:38
@gvanrossum
Copy link
Member Author

Thanks @sixolet and @jkleint!

... # Return a sequence of Ts here
else:
assert False, "Unsupported argument %r" % (index,)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just inherit from Generic[T]? Otherwise, this code would fail with Signature of "__getitem__" incompatible with supertype "Sequence".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that's kind of the point (though I agree it's pretty implicit here).

pass # Don't put code here

# Actual implementation goes last, without @overload.
# It may or may not have type hints; if it does,
Copy link
Contributor

@pkch pkch Apr 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #3160 for my concerns with both untyped and typed implementation. Maybe worth warning in the docs that untyped definitions result in the assumption of Any for each of the arguments (at least at the moment) -- that's if the body is even checked at all.

yet) using the ``@overload`` decorator. For example, we can define an
``abs`` function that works for both ``int`` and ``float`` arguments:
Sometimes the types in a function depend on each other in ways that
can't be captured with a simple ``Union``. For example, the
Copy link
Contributor

@pkch pkch Apr 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe "can't be captured with a Union or generics"?

pass # Don't put code here

# All overloads and the implementation must be adjacent
# in the source file, and overload order may matter.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #1270 (comment) for some background.

my_abs(-2) # 2 (int)
my_abs(-1.5) # 1.5 (float)
they still define a single runtime object. There is no multiple
dispatch happening, and you must manually handle the different types
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add that using @functools.singledispatch with @overloaded is not yet supported.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, @overload is not limited to a single argument, and at the type system level you can totally express multi-dispatch with it.

my_abs = abs
my_abs(-2) # 2 (int)
my_abs(-1.5) # 1.5 (float)
they still define a single runtime object. There is no multiple
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and also: this is single dispatch rather than multiple dispatch, since only one argument determines the implementation. But the sentence should apply to both single and multiple dispatch of course.

@gvanrossum
Copy link
Member Author

Since I already landed this version, feel free to submit a PR with proposed improvements. (Though I will be on vacation through Monday.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants